// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 

using System;
using System.Drawing.Imaging;
using System.IO;
using System.Reflection;
using System.Web;
using System.Xml;
using System.Xml.Schema;
using GeoAPI.Geometries;
using SharpMap.Layers;
using System.Collections.Generic;

namespace SharpMap.Web.Wms
{
    /// <summary>
    /// Class for generating the WmsCapabilities Xml
    /// </summary>
    public class ServerCapabilities : Capabilities
    {
        private const string wmsNamespaceURI = "http://www.opengis.net/wms";
        private const string xlinkNamespaceURI = "http://www.w3.org/1999/xlink";

        /// <summary>
        /// Generates a capabilities file from a map object for use in WMS services
        /// </summary>
        /// <remarks>The capabilities document uses the v1.3.0 OpenGIS WMS specification</remarks>
        /// <param name="map">The map to create capabilities for</param>
        /// <param name="serviceDescription">Additional description of WMS</param>
        /// <returns>Returns XmlDocument describing capabilities</returns>
        public static XmlDocument GetCapabilities(Map map, Capabilities.WmsServiceDescription serviceDescription)
        {
            XmlDocument capabilities = new XmlDocument();


            //Set XMLSchema
            //capabilities.Schemas.Add(GetCapabilitiesSchema());

            //Instantiate an XmlNamespaceManager object.
            //System.Xml.XmlNamespaceManager xmlnsManager = new System.Xml.XmlNamespaceManager(capabilities.NameTable);
            //xmlnsManager.AddNamespace(xlinkNamespaceURI, "urn:Books");

            //Insert XML tag
            capabilities.InsertBefore(capabilities.CreateXmlDeclaration("1.0", "UTF-8", string.Empty),
                                      capabilities.DocumentElement);
            capabilities.AppendChild(
                capabilities.CreateComment("Capabilities generated by SharpMap v. " +
                                           Assembly.GetExecutingAssembly().GetName().Version));
            //Create root node
            XmlNode RootNode = capabilities.CreateNode(XmlNodeType.Element, "WMS_Capabilities", wmsNamespaceURI);
            RootNode.Attributes.Append(CreateAttribute("version", "1.3.0", capabilities));

            XmlAttribute attr = capabilities.CreateAttribute("xmlns", "xsi", "http://www.w3.org/2000/xmlns/");
            attr.InnerText = "http://www.w3.org/2001/XMLSchema-instance";
            RootNode.Attributes.Append(attr);

            RootNode.Attributes.Append(CreateAttribute("xmlns:xlink", xlinkNamespaceURI, capabilities));
            XmlAttribute attr2 = capabilities.CreateAttribute("xsi", "schemaLocation",
                                                              "http://www.w3.org/2001/XMLSchema-instance");
            attr2.InnerText = "http://schemas.opengis.net/wms/1.3.0/capabilities_1_3_0.xsd";
            RootNode.Attributes.Append(attr2);

            //Build Service node
            RootNode.AppendChild(GenerateServiceNode(ref serviceDescription, capabilities));

            //Build Capability node
            RootNode.AppendChild(GenerateCapabilityNode(map, capabilities, serviceDescription.PublicAccessURL));

            capabilities.AppendChild(RootNode);

            //TODO: Validate output against schema

            return capabilities;
        }

        private static XmlNode GenerateServiceNode(ref WmsServiceDescription serviceDescription,
                                                   XmlDocument capabilities)
        {
            //XmlNode ServiceNode = capabilities.CreateNode(XmlNodeType.Element, "Service", "");
            XmlElement ServiceNode = capabilities.CreateElement("Service", wmsNamespaceURI);
            ServiceNode.AppendChild(CreateElement("Name", "WMS", capabilities, false, wmsNamespaceURI));
            ServiceNode.AppendChild(CreateElement("Title", serviceDescription.Title, capabilities, false,
                                                  wmsNamespaceURI)); //Add WMS Title
            if (!String.IsNullOrEmpty(serviceDescription.Abstract)) //Add WMS abstract
                ServiceNode.AppendChild(CreateElement("Abstract", serviceDescription.Abstract, capabilities, false,
                                                      wmsNamespaceURI));
            if (serviceDescription.Keywords != null && serviceDescription.Keywords.Length > 0) //Add keywords
            {
                XmlElement KeywordListNode = capabilities.CreateElement("KeywordList", wmsNamespaceURI);
                foreach (string keyword in serviceDescription.Keywords)
                    KeywordListNode.AppendChild(CreateElement("Keyword", keyword, capabilities, false, wmsNamespaceURI));
                ServiceNode.AppendChild(KeywordListNode);
            }
            //Add Online resource
            XmlElement OnlineResourceNode = GenerateOnlineResourceElement(capabilities,
                                                                          serviceDescription.OnlineResource);
            ServiceNode.AppendChild(OnlineResourceNode);

            //Add ContactInformation info
            XmlElement ContactInfoNode = GenerateContactInfoElement(capabilities, serviceDescription.ContactInformation);
            if (ContactInfoNode.HasChildNodes)
                ServiceNode.AppendChild(ContactInfoNode);

            if (serviceDescription.Fees != null && serviceDescription.Fees != string.Empty)
                ServiceNode.AppendChild(CreateElement("Fees", serviceDescription.Fees, capabilities, false,
                                                      wmsNamespaceURI));
            if (serviceDescription.AccessConstraints != null && serviceDescription.AccessConstraints != string.Empty)
                ServiceNode.AppendChild(CreateElement("AccessConstraints", serviceDescription.AccessConstraints,
                                                      capabilities, false, wmsNamespaceURI));
            if (serviceDescription.LayerLimit > 0)
                ServiceNode.AppendChild(CreateElement("LayerLimit", serviceDescription.LayerLimit.ToString(),
                                                      capabilities, false, wmsNamespaceURI));
            if (serviceDescription.MaxWidth > 0)
                ServiceNode.AppendChild(CreateElement("MaxWidth", serviceDescription.MaxWidth.ToString(), capabilities,
                                                      false, wmsNamespaceURI));
            if (serviceDescription.MaxHeight > 0)
                ServiceNode.AppendChild(CreateElement("MaxHeight", serviceDescription.MaxHeight.ToString(), capabilities,
                                                      false, wmsNamespaceURI));
            return ServiceNode;
        }

        private static XmlNode GenerateCapabilityNode(Map map, XmlDocument capabilities, string publicWMSUrl)
        {
            string OnlineResource = "";

            if (String.IsNullOrEmpty(publicWMSUrl))
            {
                string port = HttpContext.Current.Request.Url.IsDefaultPort
                                  ? ""
                                  : ":" + HttpContext.Current.Request.Url.Port;
                OnlineResource =
                    HttpContext.Current.Server.HtmlEncode("http://" + HttpContext.Current.Request.Url.Host + port +
                                                          HttpContext.Current.Request.Url.AbsolutePath);
            }
            else
            {
                OnlineResource = publicWMSUrl;
            }

            XmlNode CapabilityNode = capabilities.CreateNode(XmlNodeType.Element, "Capability", wmsNamespaceURI);
            XmlNode RequestNode = capabilities.CreateNode(XmlNodeType.Element, "Request", wmsNamespaceURI);
            XmlNode GetCapabilitiesNode = capabilities.CreateNode(XmlNodeType.Element, "GetCapabilities",
                                                                  wmsNamespaceURI);
            //Set format of supported capabilities mime types (only text/xml supported)
            GetCapabilitiesNode.AppendChild(CreateElement("Format", "text/xml", capabilities, false, wmsNamespaceURI));
            GetCapabilitiesNode.AppendChild(GenerateDCPTypeNode(capabilities, OnlineResource));
            RequestNode.AppendChild(GetCapabilitiesNode);
            XmlNode GetFeatureInfoNode = capabilities.CreateNode(XmlNodeType.Element, "GetFeatureInfo", wmsNamespaceURI);
            GetFeatureInfoNode.AppendChild(CreateElement("Format", "text/plain", capabilities, false, wmsNamespaceURI));
            GetFeatureInfoNode.AppendChild(CreateElement("Format", "text/json", capabilities, false, wmsNamespaceURI));
            GetFeatureInfoNode.AppendChild(GenerateDCPTypeNode(capabilities, OnlineResource));
            RequestNode.AppendChild(GetFeatureInfoNode);
            XmlNode GetMapNode = capabilities.CreateNode(XmlNodeType.Element, "GetMap", wmsNamespaceURI);
            //Add supported fileformats. Return the ones that GDI+ supports
            foreach (ImageCodecInfo encoder in ImageCodecInfo.GetImageEncoders())
                GetMapNode.AppendChild(CreateElement("Format", encoder.MimeType, capabilities, false, wmsNamespaceURI));

            GetMapNode.AppendChild(GenerateDCPTypeNode(capabilities, OnlineResource));

            RequestNode.AppendChild(GetMapNode);
            CapabilityNode.AppendChild(RequestNode);
            XmlElement exceptionNode = capabilities.CreateElement("Exception", wmsNamespaceURI);
            exceptionNode.AppendChild(CreateElement("Format", "text/xml", capabilities, false, wmsNamespaceURI));
            CapabilityNode.AppendChild(exceptionNode); //Add supported exception types

            //Build layerlist

            XmlNode LayerRootNode = capabilities.CreateNode(XmlNodeType.Element, "Layer", wmsNamespaceURI);
            LayerRootNode.AppendChild(CreateElement("Title", "SharpMap", capabilities, false, wmsNamespaceURI));
            LayerRootNode.AppendChild(CreateElement("CRS", "EPSG:" + map.Layers[0].SRID, capabilities, false,
                                                    wmsNamespaceURI)); //TODO
            LayerRootNode.AppendChild(GenerateBoundingBoxElement(map.GetExtents(), map.Layers[0].SRID, capabilities));
                        
            XmlElement geoBox = capabilities.CreateElement("EX_GeographicBoundingBox", wmsNamespaceURI);

            //Using default values here. This should be changed when projection library is complete
            string minX = "-180";
            string minY = "-90";
            string maxX = "180";
            string maxY = "90";

            geoBox.AppendChild(CreateElement("westBoundLongitude", minX, capabilities, false, wmsNamespaceURI));
            geoBox.AppendChild(CreateElement("southBoundLatitude", minY, capabilities, false, wmsNamespaceURI));
            geoBox.AppendChild(CreateElement("eastBoundLongitude", maxX, capabilities, false, wmsNamespaceURI));
            geoBox.AppendChild(CreateElement("northBoundLatitude", maxY, capabilities, false, wmsNamespaceURI));

            //The above way to respresent the boundingbox is correct and replace the incorrect way below. 
            //For downward compatibility I will keep the old code.
            geoBox.Attributes.Append(CreateAttribute("minx", minX, capabilities));
            geoBox.Attributes.Append(CreateAttribute("miny", minY, capabilities));
            geoBox.Attributes.Append(CreateAttribute("maxx", maxX, capabilities));
            geoBox.Attributes.Append(CreateAttribute("maxy", maxY, capabilities));
            LayerRootNode.AppendChild(geoBox);

            foreach (ILayer layer in map.Layers)
                LayerRootNode.AppendChild(GetWmsLayerNode(layer, capabilities));

            CapabilityNode.AppendChild(LayerRootNode);

            return CapabilityNode;
        }

        private static XmlNode GenerateDCPTypeNode(XmlDocument capabilities, string OnlineResource)
        {
            XmlNode DcpType = capabilities.CreateNode(XmlNodeType.Element, "DCPType", wmsNamespaceURI);
            XmlNode HttpType = capabilities.CreateNode(XmlNodeType.Element, "HTTP", wmsNamespaceURI);
            XmlElement resource = GenerateOnlineResourceElement(capabilities, OnlineResource);

            XmlNode GetNode = capabilities.CreateNode(XmlNodeType.Element, "Get", wmsNamespaceURI);
            XmlNode PostNode = capabilities.CreateNode(XmlNodeType.Element, "Post", wmsNamespaceURI);
            GetNode.AppendChild(resource.Clone());
            PostNode.AppendChild(resource);
            HttpType.AppendChild(GetNode);
            HttpType.AppendChild(PostNode);
            DcpType.AppendChild(HttpType);
            return DcpType;
        }

        private static XmlElement GenerateOnlineResourceElement(XmlDocument capabilities, string OnlineResource)
        {
            XmlElement resource = capabilities.CreateElement("OnlineResource", wmsNamespaceURI);
            XmlAttribute attrType = capabilities.CreateAttribute("xlink", "type", xlinkNamespaceURI);
            attrType.Value = "simple";
            resource.Attributes.Append(attrType);
            XmlAttribute href = capabilities.CreateAttribute("xlink", "href", xlinkNamespaceURI);
            href.Value = OnlineResource;
            resource.Attributes.Append(href);
            XmlAttribute xmlns = capabilities.CreateAttribute("xmlns:xlink");
            xmlns.Value = xlinkNamespaceURI;
            resource.Attributes.Append(xmlns);
            return resource;
        }

        private static XmlElement GenerateContactInfoElement(XmlDocument capabilities, WmsContactInformation info)
        {
            XmlElement infoNode = capabilities.CreateElement("ContactInformation", wmsNamespaceURI);

            //Add primary person
            XmlElement cpp = capabilities.CreateElement("ContactPersonPrimary", wmsNamespaceURI);
            if (info.PersonPrimary.Person != null && info.PersonPrimary.Person != String.Empty)
                cpp.AppendChild(CreateElement("ContactPerson", info.PersonPrimary.Person, capabilities, false,
                                              wmsNamespaceURI));
            if (info.PersonPrimary.Organisation != null && info.PersonPrimary.Organisation != String.Empty)
                cpp.AppendChild(CreateElement("ContactOrganization", info.PersonPrimary.Organisation, capabilities,
                                              false, wmsNamespaceURI));
            if (cpp.HasChildNodes)
                infoNode.AppendChild(cpp);

            if (info.Position != null && info.Position != string.Empty)
                infoNode.AppendChild(CreateElement("ContactPosition", info.Position, capabilities, false,
                                                   wmsNamespaceURI));

            //Add address
            XmlElement ca = capabilities.CreateElement("ContactAddress", wmsNamespaceURI);
            if (info.Address.AddressType != null && info.Address.AddressType != string.Empty)
                ca.AppendChild(CreateElement("AddressType", info.Address.AddressType, capabilities, false,
                                             wmsNamespaceURI));
            if (info.Address.Address != null && info.Address.Address != string.Empty)
                ca.AppendChild(CreateElement("Address", info.Address.Address, capabilities, false, wmsNamespaceURI));
            if (info.Address.City != null && info.Address.City != string.Empty)
                ca.AppendChild(CreateElement("City", info.Address.City, capabilities, false, wmsNamespaceURI));
            if (info.Address.StateOrProvince != null && info.Address.StateOrProvince != string.Empty)
                ca.AppendChild(CreateElement("StateOrProvince", info.Address.StateOrProvince, capabilities, false,
                                             wmsNamespaceURI));
            if (info.Address.PostCode != null && info.Address.PostCode != string.Empty)
                ca.AppendChild(CreateElement("PostCode", info.Address.PostCode, capabilities, false, wmsNamespaceURI));
            if (info.Address.Country != null && info.Address.Country != string.Empty)
                ca.AppendChild(CreateElement("Country", info.Address.Country, capabilities, false, wmsNamespaceURI));
            if (ca.HasChildNodes)
                infoNode.AppendChild(ca);

            if (info.VoiceTelephone != null && info.VoiceTelephone != string.Empty)
                infoNode.AppendChild(CreateElement("ContactVoiceTelephone", info.VoiceTelephone, capabilities, false,
                                                   wmsNamespaceURI));
            if (info.FacsimileTelephone != null && info.FacsimileTelephone != string.Empty)
                infoNode.AppendChild(CreateElement("ContactFacsimileTelephone", info.FacsimileTelephone, capabilities,
                                                   false, wmsNamespaceURI));
            if (info.ElectronicMailAddress != null && info.ElectronicMailAddress != string.Empty)
                infoNode.AppendChild(CreateElement("ContactElectronicMailAddress", info.ElectronicMailAddress,
                                                   capabilities, false, wmsNamespaceURI));

            return infoNode;
        }

        private static XmlNode GetWmsLayerNode(ILayer layer, XmlDocument doc)
        {
            XmlNode LayerNode = doc.CreateNode(XmlNodeType.Element, "Layer", wmsNamespaceURI);
            LayerNode.AppendChild(CreateElement("Name", layer.LayerName, doc, false, wmsNamespaceURI));
            LayerNode.AppendChild(CreateElement("Title", layer.LayerTitle ?? layer.LayerName, doc, false, wmsNamespaceURI));
			//if this is a vector layer with themes property set, add the Styles
            if (layer.GetType() == typeof(VectorLayer))
                if ((layer as VectorLayer).Themes != null)
                    foreach (KeyValuePair<string,SharpMap.Rendering.Thematics.ITheme> kvp in (layer as VectorLayer).Themes)
                    {
                        XmlNode styleNode = doc.CreateNode(XmlNodeType.Element, "Style", wmsNamespaceURI);
                        styleNode.AppendChild(CreateElement("Name", kvp.Key, doc, false, wmsNamespaceURI));
                        styleNode.AppendChild(CreateElement("Title", kvp.Key, doc, false, wmsNamespaceURI));
                        LayerNode.AppendChild(styleNode);
                    }
            //If this is a grouplayer, add childlayers recursively
            if (layer.GetType() == typeof (LayerGroup))
                foreach (Layer childlayer in ((LayerGroup) layer).Layers)
                    LayerNode.AppendChild(GetWmsLayerNode(childlayer, doc));
            
            LayerNode.Attributes.Append(CreateAttribute("queryable", GetQueriable(layer), doc));

            LayerNode.AppendChild(GenerateBoundingBoxElement(layer.Envelope, layer.SRID, doc));
            return LayerNode;
        }

        private static string GetQueriable(ILayer layer)
        {
            if (layer is ICanQueryLayer)
            {
                if ((layer as ICanQueryLayer).IsQueryEnabled) return "1";
            }
            return "0";
        }

        private static XmlElement GenerateBoundingBoxElement(Envelope bbox, int SRID, XmlDocument doc)
        {
            XmlElement xmlBbox = doc.CreateElement("BoundingBox", wmsNamespaceURI);
            xmlBbox.Attributes.Append(CreateAttribute("minx", bbox.Left().ToString(Map.NumberFormatEnUs), doc));
            xmlBbox.Attributes.Append(CreateAttribute("miny", bbox.Bottom().ToString(Map.NumberFormatEnUs), doc));
            xmlBbox.Attributes.Append(CreateAttribute("maxx", bbox.Right().ToString(Map.NumberFormatEnUs), doc));
            xmlBbox.Attributes.Append(CreateAttribute("maxy", bbox.Top().ToString(Map.NumberFormatEnUs), doc));
            xmlBbox.Attributes.Append(CreateAttribute("CRS", "EPSG:" + SRID, doc));
            return xmlBbox;
        }

        private static XmlAttribute CreateAttribute(string name, string value, XmlDocument doc)
        {
            XmlAttribute attr = doc.CreateAttribute(name);
            attr.Value = value;
            return attr;
        }

        private static XmlNode CreateElement(string name, string value, XmlDocument doc, bool IsXml, string namespaceURI)
        {
            XmlNode node = doc.CreateNode(XmlNodeType.Element, name, namespaceURI);
            if (IsXml)
                node.InnerXml = value;
            else
                node.InnerText = value;
            return node;
        }

        internal static XmlDocument CreateXml()
        {
            XmlDocument capabilities = new XmlDocument();
            //Set XMLSchema
            capabilities.Schemas = new XmlSchemaSet();
            capabilities.Schemas.Add(GetCapabilitiesSchema());

            return capabilities;
        }

        private static XmlSchema GetCapabilitiesSchema()
        {
            //Get XML Schema
            Stream stream =
                Assembly.GetExecutingAssembly().GetManifestResourceStream(
                    "SharpMap.Web.Wms.Schemas._1._3._0.capabilities_1_3_0.xsd");
            XmlSchema schema = XmlSchema.Read(stream, ValidationError);
            stream.Close();
            return schema;
        }

        private static void ValidationError(object sender, ValidationEventArgs arguments)
        {
        }

        //#region Nested type: WmsContactInformation

        ///// <summary>
        ///// Stores contact metadata about WMS service
        ///// </summary>
        //public struct WmsContactInformation
        //{
        //    /// <summary>
        //    /// Address
        //    /// </summary>
        //    public ContactAddress Address;

        //    /// <summary>
        //    /// Email address
        //    /// </summary>
        //    public string ElectronicMailAddress;

        //    /// <summary>
        //    /// Fax number
        //    /// </summary>
        //    public string FacsimileTelephone;

        //    /// <summary>
        //    /// Primary contact person
        //    /// </summary>
        //    public ContactPerson PersonPrimary;

        //    /// <summary>
        //    /// Position of contact person
        //    /// </summary>
        //    public string Position;

        //    /// <summary>
        //    /// Telephone
        //    /// </summary>
        //    public string VoiceTelephone;

        //    #region Nested type: ContactAddress

        //    /// <summary>
        //    /// Information about a contact address for the service.
        //    /// </summary>
        //    public struct ContactAddress
        //    {
        //        /// <summary>
        //        /// Contact address
        //        /// </summary>
        //        public string Address;

        //        /// <summary>
        //        /// Type of address (usually "postal").
        //        /// </summary>
        //        public string AddressType;

        //        /// <summary>
        //        /// Contact City
        //        /// </summary>
        //        public string City;

        //        /// <summary>
        //        /// Country of contact address
        //        /// </summary>
        //        public string Country;

        //        /// <summary>
        //        /// Zipcode of contact
        //        /// </summary>
        //        public string PostCode;

        //        /// <summary>
        //        /// State or province of contact
        //        /// </summary>
        //        public string StateOrProvince;
        //    }

        //    #endregion

        //    #region Nested type: ContactPerson

        //    /// <summary>
        //    /// Information about a contact person for the service.
        //    /// </summary>
        //    public struct ContactPerson
        //    {
        //        /// <summary>
        //        /// Organisation of primary person
        //        /// </summary>
        //        public string Organisation;

        //        /// <summary>
        //        /// Primary contact person
        //        /// </summary>
        //        public string Person;
        //    }

        //    #endregion
        //}

        //#endregion

        //#region Nested type: WmsServiceDescription

        ///// <summary>
        ///// The Wms Service Description stores metadata parameters for a WMS service
        ///// </summary>
        //public struct WmsServiceDescription
        //{
        //    /// <summary>
        //    /// Optional narrative description providing additional information
        //    /// </summary>
        //    public string Abstract;

        //    /// <summary>
        //    /// <para>The optional element "AccessConstraints" may be omitted if it do not apply to the server. If
        //    /// the element is present, the reserved word "none" (case-insensitive) shall be used if there are no
        //    /// access constraints, as follows: "none".</para>
        //    /// <para>When constraints are imposed, no precise syntax has been defined for the text content of these elements, but
        //    /// client applications may display the content for user information and action.</para>
        //    /// </summary>
        //    public string AccessConstraints;

        //    /// <summary>
        //    /// Optional WMS contact information
        //    /// </summary>
        //    public WmsContactInformation ContactInformation;

        //    /// <summary>
        //    /// The optional element "Fees" may be omitted if it do not apply to the server. If
        //    /// the element is present, the reserved word "none" (case-insensitive) shall be used if there are no
        //    /// fees, as follows: "none".
        //    /// </summary>
        //    public string Fees;

        //    /// <summary>
        //    /// Optional list of keywords or keyword phrases describing the server as a whole to help catalog searching
        //    /// </summary>
        //    public string[] Keywords;

        //    /// <summary>
        //    /// Maximum number of layers allowed (0=no restrictions)
        //    /// </summary>
        //    public uint LayerLimit;

        //    /// <summary>
        //    /// Maximum height allowed in pixels (0=no restrictions)
        //    /// </summary>
        //    public uint MaxHeight;

        //    /// <summary>
        //    /// Maximum width allowed in pixels (0=no restrictions)
        //    /// </summary>
        //    public uint MaxWidth;

        //    /// <summary>
        //    /// Mandatory Top-level web address of service or service provider.
        //    /// </summary>
        //    public string OnlineResource;

        //    /// <summary>
        //    /// Mandatory Human-readable title for pick lists
        //    /// </summary>
        //    public string Title;

        //    /// <summary>
        //    /// Public url to access the service in case service is hosted behind firewall
        //    /// </summary>
        //    public string PublicAccessURL;

        //    /// <summary>
        //    /// Initializes a WmsServiceDescription object
        //    /// </summary>
        //    /// <param name="title">Mandatory Human-readable title for pick lists</param>
        //    /// <param name="onlineResource">Top-level web address of service or service provider.</param>
        //    public WmsServiceDescription(string title, string onlineResource)
        //        : this(title,onlineResource,null)
        //    {
        //    }

        //    /// <summary>
        //    /// Initializes a WmsServiceDescription object
        //    /// </summary>
        //    /// <param name="title">Mandatory Human-readable title for pick lists</param>
        //    /// <param name="onlineResource">Top-level web address of service or service provider.</param>
        //    /// <param name="publicWMSAccessUrl">Public URL to use when accessing the service in case it is hosted behind a firewall</param>
        //    public WmsServiceDescription(string title, string onlineResource, string publicWMSAccessUrl)
        //    {
        //        Title = title;
        //        OnlineResource = onlineResource;
        //        Keywords = new string[0];
        //        Abstract = "";
        //        ContactInformation = new WmsContactInformation();
        //        Fees = "";
        //        AccessConstraints = "";
        //        LayerLimit = 0;
        //        MaxWidth = 0;
        //        MaxHeight = 0;
        //        PublicAccessURL = publicWMSAccessUrl;
        //    }
        //}

        //#endregion
    }
}
